<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>GTK+中的构件（GTK+ Widgets）</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="GUI, Widgets, GTK+ library, C">
<meta nam="description" content="GTK+ Widgets">
<meta name="language" content="zh, en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>GTK+中的构件（GTK+ Widgets）</h1>

<p>
在本章的GTK+程序设计教程中，我们将带领大家去更深一步的去领略GTK+构件的魅力。 
</p>

<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div>

<p>
毫无疑问，构件是建立一个GUI应用程序的基础。在很多年来的发展下，一些特定的构件逐渐就成为了大多数编程工具集（toolkits）和几乎所有操作系统的公用标准了。譬如说，按钮，选择框或者是一个滑动条。至于像GTK+这样的编程工具集，一开始他的设计人员所抱的哲学态度是：保持构件的数量在一个合理的范围内。正是由于这一点，越来越多的专用构件，被抽象为通用的构件，供大家使用。 
</p>


<h2>GtkButton</h2>

<p>
GtkButton 是一种很简单易用的构件，通常被用于触发一个动作。 
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;


int main( int argc, char *argv[])
{
  GtkWidget *window;
  GtkWidget *fixed;
  GtkWidget *button;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(window), "GtkButton");
  gtk_window_set_default_size(GTK_WINDOW(window), 230, 150);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

  fixed = gtk_fixed_new();
  gtk_container_add(GTK_CONTAINER(window), fixed);

  button = gtk_button_new_with_label("Quit");

  gtk_fixed_put(GTK_FIXED(fixed), button, 50, 50);
  gtk_widget_set_size_request(button, 80, 35);

  g_signal_connect(G_OBJECT(button), "clicked", 
      G_CALLBACK(gtk_main_quit), G_OBJECT(window));

  g_signal_connect_swapped(G_OBJECT(window), "destroy", 
      G_CALLBACK(gtk_main_quit), NULL);

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
</pre>

<p>
上面的这个程序示例就是向大家展示一个按钮构件被放置在一个fixed容器构件里。当你按下那个按钮后，程序就会退出。 
</p>

<pre class="explanation">
 button = gtk_button_new_with_label("Quit");
</pre>

<p>
上面这段代码生成了一个带有标签的 <b class="keyword">GtkButton</b> 构件。 
</p>

<pre class="explanation">
  g_signal_connect(G_OBJECT(button), "clicked", 
      G_CALLBACK(gtk_main_quit), G_OBJECT(window));
</pre>

<p>
然后我们再把信号<b class="keyword">clicked</b> 与这个按钮进行绑定。这个信号会引发函数<b class="keyword">gtk_main_quit()</b>的调用执行，这个函数的功能正是要使整个程序终止退出。 

</p>

<br>
<img src="../images/gtkbutton.png" alt="GtkButton">
<div class="figure">Figure: GtkButton</div>

<h2>GtkCheckButton</h2>

<p>
GtkCheckButton 同样也是一个构件，他有两种状态。“开”和“关”，开表示一个可见的复选标记。 
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;


void toggle_title(GtkWidget *widget, gpointer window)
{
  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
      gtk_window_set_title(window, "GtkCheckButton");	
  } else {
      gtk_window_set_title(window, "");
  }
}

int main(int argc, char** argv) {

  GtkWidget *window;
  GtkWidget *frame;
  GtkWidget *check;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 230, 150);
  gtk_window_set_title(GTK_WINDOW(window), "GtkCheckButton");


  frame = gtk_fixed_new();
  gtk_container_add(GTK_CONTAINER(window), frame);


  check = gtk_check_button_new_with_label("Show title");
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
  GTK_WIDGET_UNSET_FLAGS(check, GTK_CAN_FOCUS);
  gtk_fixed_put(GTK_FIXED(frame), check, 50, 50);

  g_signal_connect_swapped(window, "destroy",
          G_CALLBACK(gtk_main_quit), NULL);

  g_signal_connect(check, "clicked", 
          G_CALLBACK(toggle_title), (gpointer) window);

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
</pre>

<p>
我们将要展示的功能是：标题栏的显示状态根据构件  <b class="keyword">GtkCheckButton</b>的状态变化而变化。
</p>

<pre class="explanation">
 check = gtk_check_button_new_with_label("Show title");
 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
</pre>

<p>
一个<b class="keyword">GtkCheckButton</b> 构件被生成了并且默认为已标记（状态为开）， 因为我们想一开始标题栏是默认显示的。 
</p>

<pre class="explanation">
 GTK_WIDGET_UNSET_FLAGS(check, GTK_CAN_FOCUS);
</pre>

<p>
这行代码是取消了对复选框的默认锁定，这样做的原因很简单，是因为我不大喜欢在复选框上真的“罩”上一个“框”，我个人认为那样不大好看。：） 

</p>


<pre class="explanation">
 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
    gtk_window_set_title(window, "GtkCheckButton");	
 } else {
    gtk_window_set_title(window, "");
 }
</pre>

<p>
这样的话，功能就完成了：标题栏的显示状态根据构件 <b class="keyword">GtkCheckButton</b>的状态变化而变化。 
</p>

<br>
<img src="../images/gtkcheckbutton.png" alt="GtkCheckButton">
<div class="figure">Figure: GtkCheckButton</div>


<h2>GtkFrame</h2>

<p>
GtkFrame 是一种装饰性的框架，还可以为他设置一个标签（可有可无）。 
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;


int main( int argc, char *argv[])
{

  GtkWidget *window;
  GtkWidget *table;

  GtkWidget *frame1;
  GtkWidget *frame2;
  GtkWidget *frame3;
  GtkWidget *frame4;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 250, 250);
  gtk_window_set_title(GTK_WINDOW(window), "GtkFrame");

  gtk_container_set_border_width(GTK_CONTAINER(window), 10);

  table = gtk_table_new(2, 2, TRUE);
  gtk_table_set_row_spacings(GTK_TABLE(table), 10);
  gtk_table_set_col_spacings(GTK_TABLE(table), 10);
  gtk_container_add(GTK_CONTAINER(window), table);


  frame1 = gtk_frame_new("Shadow In");
  gtk_frame_set_shadow_type(GTK_FRAME(frame1), GTK_SHADOW_IN);
  frame2 = gtk_frame_new("Shadow Out");
  gtk_frame_set_shadow_type(GTK_FRAME(frame2), GTK_SHADOW_OUT);
  frame3 = gtk_frame_new("Shadow Etched In");
  gtk_frame_set_shadow_type(GTK_FRAME(frame3), GTK_SHADOW_ETCHED_IN);
  frame4 = gtk_frame_new("Shadow Etched Out");
  gtk_frame_set_shadow_type(GTK_FRAME(frame4), GTK_SHADOW_ETCHED_OUT);


  gtk_table_attach_defaults(GTK_TABLE(table), frame1, 0, 1, 0, 1);
  gtk_table_attach_defaults(GTK_TABLE(table), frame2, 0, 1, 1, 2);
  gtk_table_attach_defaults(GTK_TABLE(table), frame3, 1, 2, 0, 1);
  gtk_table_attach_defaults(GTK_TABLE(table), frame4, 1, 2, 1, 2);

  g_signal_connect_swapped(G_OBJECT(window), "destroy",
        G_CALLBACK(gtk_main_quit), G_OBJECT(window));

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
</pre>

<p>
这个示例向我们展示了四种不同风格的frame框架。这些框架构件是利用表格布局法进行布局的。 
</p>

<pre class="explanation">
 frame1 = gtk_frame_new("Shadow In");
 gtk_frame_set_shadow_type(GTK_FRAME(frame1), GTK_SHADOW_IN);
</pre>

<p>
我们生成了一个<b class="keyword">GtkFrame</b>构件，并且还为他设置了阴影种类（shadow type）。 
</p>


<br>
<img src="../images/frames.png" alt="GtkFrame">
<div class="figure">Figure: GtkFrame</div>


<h2>GtkLabel</h2>

<p>
GtkLabel 的功能很明显，是用来显示文字的。 
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;


int main( int argc, char *argv[])
{
  GtkWidget *window;
  GtkWidget *label;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_title(GTK_WINDOW(window), "Nymphetamine");
  gtk_window_set_default_size(GTK_WINDOW(window), 350, 400);

  label = gtk_label_new("Cold was my soul\n\
Untold was the pain\n\
I faced when you left me\n\
A rose in the rain....\n\
So I swore to the razor\n\
That never, enchained\n\
Would your dark nails of faith\n\
Be pushed through my veins again\n\
\n\
Bared on your tomb\n\
I'm a prayer for your loneliness\n\
And would you ever soon\n\
Come above onto me?\n\
For once upon a time\n\
On the binds of your lowliness\n\
I could always find the slot for your sacred key ");

  gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
  gtk_container_add(GTK_CONTAINER(window), label);

  g_signal_connect_swapped(window, "destroy",
      G_CALLBACK (gtk_main_quit), NULL);

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
</pre>

<p>
这个示例向我们展示了一首歌的歌词。 
</p>

<pre class="explanation">
  label = gtk_label_new("Cold was my soul\n\
Untold was the pain\n\
...
</pre>

<p>
我们这里生成了一个 <b class="keyword">GtkLabel</b> 构件。我们利用了换行符来完成多行显示的效果。
</p>


<pre class="explanation">
 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
</pre>

<p>
哈哈`~我们把标签放在中央，大功告成！ 


</p>

<br>
<img src="../images/label.png" alt="GtkLabel">
<div class="figure">Figure: GtkLabel</div>


<p>
在 GtkLabel 构件中我们也能够使用语法 markup 。（就是用来改变文字样式的语法）下面的这个示例就是展示我们是如何完成这个工作的。 
</p>

<pre class="code">
#include &lt;gtk/gtk.h&gt;


int main( int argc, char *argv[])
{
  GtkWidget *window;
  GtkWidget *label;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_title(GTK_WINDOW(window), "markup label");

  char *str = "&lt;b&gt;ZetCode&lt;/b&gt;, Knowledge only matters";

  label = gtk_label_new(NULL);
  gtk_label_set_markup(GTK_LABEL(label), str);

  gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
  gtk_container_add(GTK_CONTAINER(window), label);
  gtk_widget_show(label);

  gtk_window_set_default_size(GTK_WINDOW(window), 300, 100);

  g_signal_connect(window, "destroy",
      G_CALLBACK (gtk_main_quit), NULL);

  gtk_widget_show(window);

  gtk_main();

  return 0;
}
</pre>

<p>
这个例子是，我们让一部分文字有突出的效果。 
</p>

<pre class="explanation">
 char *str = "&lt;b&gt;ZetCode&lt;/b&gt;, Knowledge only matters";
</pre>

<p>
这就是我们要显示的文字内容。 
</p>

<pre class="explanation">
  label = gtk_label_new(NULL);
  gtk_label_set_markup(GTK_LABEL(label), str);
</pre>

<p>
我们生成了一个空的标签构件，然后把样式化的文字（markup text）添加到标签构件里。大功再次告成！ －＿－！
</p>


<br>
<img src="../images/markup.png" alt="markup label">
<div class="figure">Figure: markup label</div>
<br>


<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡ 
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified March 16, 2008  <span class="copyright">&copy; 2007 - 2012 Jan Bodnar</span>
<span class="copyright">Translation &copy; 2008 chinalmy</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>


